package org.fhkoeln.sgdm.sudoku.logic;

import java.util.HashMap;
import java.util.Vector;

import org.fhkoeln.sgdm.sudoku.gui.TippFrame;

public class FindPairMarkups
{
	public boolean findPairings(SudokuField dataSource)
	{
		boolean rt = false;
		HashMap<String, Vector<Integer>> fieldData = new HashMap<String, Vector<Integer>>();
		
		//Step 1: Create possible values for all empty fields
		for(int i = 0; i < 9; i ++)
		{
			for(int j = 0; j < 9; j ++)
			{
				if(dataSource.values[j][i] == 0)
				{
					fieldData.put("" + i + "" + j, createPossibleValues(dataSource, i, j));
				}
			}
		}
		
		int lastVal = 0;
		do
		{
			lastVal = getFieldSize(fieldData);
			for(int i = 0; i < 3; i++)
			{
				for(int j = 0; j < 3; j ++)
				{
					evaluateQuad(fieldData, i, j);
				}
			}
		}while(lastVal != getFieldSize(fieldData));
		
		//now check if in any quad is a field with only one posibillity left:
		//Get the first possible digit for the first free field
		for(int i = 0; i < 3; i++)
		{
			for(int j = 0; j < 3; j ++)
			{
				if(checkQuad(fieldData, i, j)){
					rt = true;
				}
			}
		}
		
		
		return rt;
	}
	
	int getFieldSize(HashMap<String, Vector<Integer>> fieldData)
	{
		int val = 0;
		
		for(String str : fieldData.keySet())
		{
			val += fieldData.get(str).size();
		}
		
		return val;
	}
	
	private boolean checkQuad(HashMap<String, Vector<Integer>> fieldData, int quadX, int quadY)
	{
		boolean rt = false;
		//Find values that will only block a single line or row
		for(int i = quadX * 3; i < (quadX + 1) * 3; i ++)
		{
			for(int j = quadY * 3; j < (quadY + 1) * 3; j++)
			{
				if(fieldData.containsKey("" + i + "" + j))
				{
					for(Integer curVal : fieldData.get("" + i + "" + j))
					{
						Vector<String> occs = getOccurances(fieldData, quadX, quadY, curVal);
						if(occs.size() == 1)
						{
							//We found a value trough paring
							TippFrame.getInstance().addText("Tipp: Pairing X: " + (i + 1) + " Y: " + (j + 1) + " Value: " 
									+ curVal);
							rt = true;
						}
					}
				}
			}
		}
		return rt;
	}
	
	private void evaluateQuad(HashMap<String, Vector<Integer>> fieldData, int quadX, int quadY)
	{
		//Find values that will only block a single line or row
		for(int i = quadX * 3; i < (quadX + 1) * 3; i ++)
		{
			for(int j = quadY * 3; j < (quadY + 1) * 3; j++)
			{
				if(fieldData.containsKey("" + i + "" + j))
				{
					Vector<Integer> valsRow = new Vector<Integer>();
					Vector<Integer> valsColumn = new Vector<Integer>();
					for(Integer curVal : fieldData.get("" + i + "" + j))
					{
						//curVal is now the int we are checking
						//find all other occurances in this quadrant
						Vector<String> occs = getOccurances(fieldData, quadX, quadY, curVal);
						if(occs.size() < 2 || occs.size() > 3)
						{
							continue;
						}
						//Check if the occurancies are all in one line or one column
						//line y must be equal
						boolean difference = false;
						for(String checker : occs)
						{
							int curY = Integer.parseInt("" + checker.charAt(1));
							if(curY != j)
							{
								difference = true;
							}
						}
						if(!difference)
						{
							valsRow.add(curVal);
						}
						difference = false;
						for(String checker : occs)
						{
							int curX = Integer.parseInt("" + checker.charAt(0));
							if(curX != i)
							{
								difference = true;
							}
						}
						if(!difference)
						{
							valsColumn.add(curVal);
						}
						
					}
					for(Integer val : valsRow)
					{
						removeFromRow(fieldData, quadX, j, val);
					}
					for(Integer val : valsColumn)
					{
						removeFromColumn(fieldData, quadY, i, val);
					}
				}
			}
		}
	}
	
	private void removeFromRow(HashMap<String, Vector<Integer>> fieldData, int excludeQuadX, int y, Integer valToRemove)
	{
		for(int i = 0; i < 9; i ++)
		{
			//remove the 3 values that belong to the quad where we checked:
			if((i >= excludeQuadX * 3) && (i < (excludeQuadX + 1) * 3))
			{
				
			}
			else
			{
				if(fieldData.containsKey("" + i + "" + y))
				{
					fieldData.get("" + i + "" + y).remove(valToRemove);
					System.out.println("Removed: " + valToRemove + " from X:" + i + " Y: " + y);
				}
			}
		}
	}
	
	private void removeFromColumn(HashMap<String, Vector<Integer>> fieldData, int excludeQuadY, int x, Integer valToRemove)
	{
		for(int j = 0; j < 9; j ++)
		{
			//remove the 3 values that belong to the quad where we checked:
			if((j >= excludeQuadY * 3) && (j < (excludeQuadY + 1) * 3))
			{
				
			}
			else
			{
				if(fieldData.containsKey("" + x + "" + j))
				{
					fieldData.get("" + x + "" + j).remove(valToRemove);
					System.out.println("Removed: " + valToRemove + " from X:" + x + " Y: " + j);
				}
			}
		}
	}
	
	private Vector<String> getOccurances(HashMap<String, Vector<Integer>> fieldData, int quadX, int quadY, Integer valToLookFor)
	{
		Vector<String> found = new Vector<String>();
		//Find values that will only block a single line or row
		for(int i = quadX * 3; i < (quadX + 1) * 3; i ++)
		{
			for(int j = quadY * 3; j < (quadY + 1) * 3; j++)
			{
				if(fieldData.containsKey("" + i + "" + j))
				{
					for(Integer curVal : fieldData.get("" + i + "" + j))
					{
						if(curVal.equals(valToLookFor))
						{
							found.add("" + i + "" + j);
						}
					}
				}
			}
		}
		return found;
	}
	
	
	private Vector<Integer> createPossibleValues(SudokuField dataSource, int x, int y)
	{
		Vector<Integer> possVals = createIntVec();
		//////CHECK FOR THE ROW//////
		//check the row if all other fields are filled already:
		for(int i = 0; i < 9; i ++)
		{
			//do not check the field we want to make the baby check for
			if(dataSource.values[y][i] != 0)
			{
				removeFromVec(new Integer(dataSource.values[y][i]), possVals);
			}
		}
		//////CHECK FOR THE COLUMN//////
		//check the column if all other fields are filled already:
		for(int i = 0; i < 9; i ++)
		{
			//do not check the field we want to make the baby check for
			if(y != i)
			{
				if(dataSource.values[i][x] != 0)
				{
					removeFromVec(new Integer(dataSource.values[i][x]), possVals);
				}
			}
		}
		//////CHECK FOR THE QUAD//////
		//check the column if all other fields are filled already:
		for(int i = 0; i < 3; i ++)
		{
			for(int j = 0; j < 3; j++)
			{
				
				//do not check the field we want to make the baby check for
				if((x%3) != i || (y%3) != j)
				{
					if(dataSource.values[j + ((y/3)*3)][i + ((x/3)*3)] != 0)
					{
						removeFromVec(new Integer(dataSource.values[j + ((y/3)*3)][i + ((x/3)*3)]), possVals);
					}
				}
			}
		}
		
		return possVals;
	}
	
	private Vector<Integer> createIntVec()
	{
		Vector<Integer> vec = new Vector<Integer>();
		for(int i = 1; i <= 9; i ++ )
		{
			vec.add(new Integer(i));
		}
		return vec;
	}
	
	private void removeFromVec(Integer valToRemove, Vector<Integer> vec)
	{
		Integer val = null;
		for(Integer curVal : vec)
		{
			if(curVal.equals(valToRemove))
			{
				val = curVal;
			}
		}
		
		if(val != null)
		{
			vec.remove(val);
		}
	}
}
